﻿using Fleck;
using Microsoft.Extensions.Hosting;

namespace CabinetGrid.DeviceDriver;

public partial class ViewModel
{
    private readonly ILogger _logger;
    private readonly Core.AppConfig _appConfig;
    private readonly List<IWebSocketConnection> _webSocketClientList;
    private readonly Services.AudioService _audioService;

    private readonly List<Dtos.RFIDUHFTagDto> _rfidUHFTagList;
    private readonly List<Dev.Integration.UHFReader.IApiClient> _rfidUHFReaderList;

    private readonly List<Dtos.RFIDHFTagDto> _rfidHFTagList;
    private readonly List<Dev.Integration.HFReader.IApiClient> _rfidHFReaderList;

    private readonly Dev.Integration.Locker.IApiClient _locker;

    private readonly Dev.Integration.HFReader.IApiClient _cardReader;

    public ViewModel( ILoggerFactory loggerFactory, IConfiguration configuration, Services.AudioService audioService )
    {
        _logger = loggerFactory.CreateLogger( nameof( ViewModel ) );

        _appConfig = configuration.Get<Core.AppConfig>( );
        _appConfig.RFIDReaderList = configuration.GetSection( "RFIDReaderList" ).GetChildren( ).Select( i => i.Get<Core.RFIDReaderConfig>( ) ).ToList( );

        _audioService = audioService;

        _webSocketClientList = new( );

        _rfidUHFTagList = new( );
        _rfidUHFReaderList = new( );

        _rfidHFTagList = new( );
        _rfidHFReaderList = new( );

        _locker = new Dev.Integration.Locker.ApiClientBuilder( )
                                            .UseKind( _appConfig.Locker.Kind )
                                            .UseConfig( o =>
                                            {
                                                o.Connect.ConnectType = _appConfig.Locker.ConnectType;
                                                o.Connect.ConnectArgs = _appConfig.Locker.ConnectArgs;
#if DEBUG
                                                o.MonitorLogAction = ( level, log ) => ConsoleWirter.Debug( $"+ [locker] {log}" );
#endif
                                            } )
                                            .Build( );

        _cardReader = new Dev.Integration.HFReader.ApiClientBuilder( )
                                                  .UseReaderKind( _appConfig.CardReader.Kind )
                                                  .UseReaderConfig( o =>
                                                  {
                                                      o.Connect.ConnectType = _appConfig.CardReader.ConnectType;
                                                      o.Connect.ConnectArgs = _appConfig.CardReader.ConnectArgs;
#if DEBUG
                                                      o.MonitorLogAction = ( level, log ) => ConsoleWirter.Debug( $"+ [card reader] {log}" );
#endif
                                                  } )
                                                  .Build( );
    }

    public Core.AppConfig AppConfig => _appConfig;
    public Services.AudioService AudioService => _audioService;
    public List<IWebSocketConnection> WebSocketClientList => _webSocketClientList;

    public List<Dtos.RFIDUHFTagDto> RFIDUHFTagList => _rfidUHFTagList;
    public List<Dev.Integration.UHFReader.IApiClient> RFIDUHFReaderList => _rfidUHFReaderList;

    public List<Dtos.RFIDHFTagDto> RFIDHFTagList => _rfidHFTagList;
    public List<Dev.Integration.HFReader.IApiClient> RFIDHFReaderList => _rfidHFReaderList;

    public Dev.Integration.Locker.IApiClient Locker => _locker;

    public Dev.Integration.HFReader.IApiClient CardReader => _cardReader;
}

partial class ViewModel
{
    internal void WebSocketClientNotify( Dtos.MsgDto msg, string? client = null )
    {
        var data = msg.ToJson( );

        var query = _webSocketClientList.Where( i => i.IsAvailable );
        if ( client.HasValue( ) )
        {
            query = query.Where( i => i.ConnectionInfo.ClientIpAddress == client );
        }

        var invalidClientList = query.ToList( );
        invalidClientList.ForEach( i =>
        {
            i.Send( data );
        } );

        _logger.Debug( $"ws 发布客户端消息: {data}" );
    }

    internal void WebSocketClientNoityWithRFIDUHFTagList( string reader )
    {
        var list = _rfidUHFTagList.Where( i => i.Reader == reader );

        var msg = new Dtos.MsgDto
        {
            Cmd = "rfid_uhf_inventory_result",
            Data = new Dictionary<string, object>
            {
                ["count"] = list.Count( ),
                ["list"] = list,
            }
        };

        this.WebSocketClientNotify( msg );
    }

    internal void WebSocketClientNotifyWithLockerStateChanged( Dev.Integration.Locker.StateChangedEventArgs e )
    {
        var msg = new Dtos.MsgDto
        {
            Cmd = "locker_state_changed",
            Data = new Dictionary<string, object>
            {
                ["addr"] = e.StateInfo.Addr,
                ["no"] = e.StateInfo.No,
                ["state"] = (int)e.StateInfo.State,
            },
        };

        this.WebSocketClientNotify( msg );
    }
}


partial class ViewModel
{
    internal void ClearRFIDUHFTags( ) => _rfidUHFTagList.Clear( );
    internal void ClearRFIDUHFTags( string reader ) => _rfidUHFTagList.RemoveAll( i => i.Reader == reader );

    internal void AddOrUpdateRFIDUHFTag( Dev.Integration.UHFReader.TagInfo tag )
    {
        var find = _rfidUHFTagList.SingleOrDefault( i => i.Id == tag.Id );
        if ( find is null )
        {
            find = new Dtos.RFIDUHFTagDto
            {
                Id = tag.Id,
                Reader = tag.Reader,
                EPC = tag.EPC,
                TID = tag.TID,
                PC = tag.PC,
                AntList = new List<Dtos.RFIDUHFTagDto.AntInfo>
                {
                    new Dtos.RFIDUHFTagDto.AntInfo { AntNo = tag.AntNo, RSSI = tag.RSSI, Count = 1 }
                }
            };

            _rfidUHFTagList.Add( find );
        }
        else
        {
            var findAnt = find.AntList.SingleOrDefault( i => i.AntNo == tag.AntNo );
            if ( findAnt is null )
            {
                find.AntList.Add( new Dtos.RFIDUHFTagDto.AntInfo { AntNo = tag.AntNo, RSSI = tag.RSSI, Count = 1 } );
            }
            else
            {
                //findAnt.AntNo = tag.AntNo;
                findAnt.RSSI = tag.RSSI;
                findAnt.Count += 1;
            }
        }
    }

    internal IEnumerable<Dtos.RFIDUHFTagDto> RFIDUHFInventoryScan( string reader, byte[] antNoList, int scanCount, bool includeTID )
    {
        if ( reader.IsNullOrWhiteSpace( ) )     // 所有读写器同时盘点
        {
            this.ClearRFIDUHFTags( );

            _rfidUHFReaderList.ForEach( api =>
            {
                api.InventoryScan( o =>
                {
                    o.AntNoList = antNoList;
                    o.ScanCount = scanCount;
                    o.IncludeTID = includeTID;
                } );
            } );

            return _rfidUHFTagList;
        }
        else    // 指定读写器盘点
        {
            var api = _rfidUHFReaderList.SingleOrDefault( api => api.ReaderId.StartsWith( reader ) );
            if ( api is null ) throw new KeyNotFoundException( $"未检索到读写器: {reader}" );

            this.ClearRFIDUHFTags( reader: api.ReaderId );

            api.InventoryScan( o =>
            {
                o.AntNoList = antNoList;
                o.ScanCount = scanCount;
                o.IncludeTID = includeTID;
            } );

            return _rfidUHFTagList.Where( i => i.Reader.StartsWith( reader ) );
        }
    }

    internal bool RFIDUHFLocate( string reader, List<byte> antNoList, string epc, int durationMilliseconds )
    {
        var api = _rfidUHFReaderList.SingleOrDefault( api => api.ReaderId.StartsWith( reader ) );
        if ( api is null ) throw new KeyNotFoundException( $"未检索到读写器: {reader}" );

        var success = api.Locate( o =>
        {
            o.AntNoList = antNoList;
            o.Data = epc;
            o.DurationMilliseconds = durationMilliseconds;
        } );

        return success;
    }
}


partial class ViewModel
{
    internal void ClearRFIDHFTags( ) => _rfidHFTagList.Clear( );
    internal void ClearRFIDHFTags( string reader ) => _rfidHFTagList.RemoveAll( i => i.Reader == reader );

    internal void AddOrUpdateRFIDHFTag( Dev.Integration.HFReader.TagInfo tag )
    {
        var find = _rfidHFTagList.SingleOrDefault( i => i.UID == tag.UID );
        if ( find is null )
        {
            find = new Dtos.RFIDHFTagDto
            {
                Reader = tag.ReaderId,
                UID = tag.UID,
                BlockData = tag.BlockData,
                AntList = new List<Dtos.RFIDHFTagDto.AntInfo>
                {
                    new Dtos.RFIDHFTagDto.AntInfo { AntNo = tag.AntAddr, Count = 1 }
                }
            };

            _rfidHFTagList.Add( find );
        }
        else
        {
            var findAnt = find.AntList.SingleOrDefault( i => i.AntNo == tag.AntAddr );
            if ( findAnt is null )
            {
                find.AntList.Add( new Dtos.RFIDHFTagDto.AntInfo { AntNo = tag.AntAddr, Count = 1 } );
            }
            else
            {
                findAnt.Count += 1;
            }
        }
    }

    internal IEnumerable<Dtos.RFIDHFTagDto> RFIDHFInventoryScan( string reader, byte[] antNoList, int scanCount, bool readBlock, int blockStartIndex, int blockCount )
    {
        if ( reader.IsNullOrWhiteSpace( ) )
        {
            this.ClearRFIDHFTags( );

            _rfidHFReaderList.ForEach( api =>
            {
                var list = api.InventoryScan( o =>
                {
                    o.AntNoList = antNoList;
                    o.ScanCount = scanCount;
                    o.ReadBlock = readBlock;
                    o.BlockStartIndex = blockStartIndex;
                    o.BlockCount = blockCount;
                } );

                list.ForEach( tag => this.AddOrUpdateRFIDHFTag( tag ) );
            } );

            return _rfidHFTagList;
        }
        else    // 指定读写器盘点
        {
            var api = _rfidHFReaderList.SingleOrDefault( api => api.ReaderId.StartsWith( reader ) );
            if ( api is null ) throw new KeyNotFoundException( $"未检索到读写器: {reader}" );

            this.ClearRFIDHFTags( reader: api.ReaderId );

            var list = api.InventoryScan( o =>
            {
                o.AntNoList = antNoList;
                o.ScanCount = scanCount;
                o.ReadBlock = readBlock;
                o.BlockStartIndex = blockStartIndex;
                o.BlockCount = blockCount;
            } );

            list.ForEach( tag => this.AddOrUpdateRFIDHFTag( tag ) );

            return _rfidHFTagList.Where( i => i.Reader.StartsWith( reader ) );
        }
    }
}


partial class ViewModel
{
    internal void TestRFIDUHFReaderList( int loop )
    {
        _ = Task.Factory.StartNew( ( ) =>
        {
            foreach ( var api in _rfidUHFReaderList )
            {
                if ( api.ReaderState == Dev.Integration.UHFReader.Constants.ReaderState.Close )
                {
                    ConsoleWirter.Warning( $"读写器未启用: {api.Config.Connect.ConnectArgs}" );
                    continue;
                }

                for ( int i = 1; i <= loop; i++ )
                {
                    ConsoleWirter.Info( $"超高频读写器 第{i}轮测试..." );
                    Thread.Sleep( 1000 );

                    for ( byte ant = 1; ant <= 10; ant++ )
                    {
                        try
                        {
                            var list = api.InventoryScan( o =>
                            {
                                o.AntNoList = new byte[] { ant };
                                o.ScanCount = 1;
                            } );

                            ConsoleWirter.Success( $"读写器: {api.ReaderId}, 天线: {ant}, 标签数: {list.Count}" );
                        }
                        catch ( Exception ex )
                        {
                            ConsoleWirter.Warning( $"读写器: {api.ReaderId}, 天线: {ant}, 工作失败: {ex.Message}" );
                        }
                        finally
                        {
                            Thread.Sleep( 1000 );
                        }
                    }
                }
            }
        } );
    }

    internal void TestLocker( int loop )
    {
        _ = Task.Factory.StartNew( ( ) =>
        {
            if ( _locker.IsOpened is false )
            {
                ConsoleWirter.Warning( $"锁控未启用: {_locker.Config.Connect.ConnectArgs}" );
                return;
            }

            for ( int i = 1; i <= loop; i++ )
            {
                ConsoleWirter.Info( $"锁控 第{i}轮测试..." );
                Thread.Sleep( 1000 );

                for ( byte addr = 1; addr <= _rfidUHFReaderList.Count; addr++ )
                {
                    for ( byte no = 1; no <= 10; no++ )
                    {
                        try
                        {
                            var success = _locker.Unlock( addr, no );
                            ConsoleWirter.Success( $"锁板: {addr}, 锁号: {no}, 开锁成功" );
                        }
                        catch ( Exception ex )
                        {
                            ConsoleWirter.Warning( $"锁板: {addr}, 锁号: {no}, 开锁失败: {ex.Message}" );
                        }
                        finally
                        {
                            Thread.Sleep( 500 );
                        }
                    }
                }
            }
        } );
    }

    internal void TestCardReader( int loop )
    {
        _ = Task.Factory.StartNew( ( ) =>
        {
            if ( _cardReader.ReaderState == Dev.Integration.HFReader.Constants.ReaderState.Close )
            {
                ConsoleWirter.Warning( $"读卡器未启用: {_cardReader.ReaderConfig.Connect.ConnectArgs}" );
                return;
            }

            for ( int i = 0; i < loop; i++ )
            {
                ConsoleWirter.Info( $"读卡器 第{i}轮测试..." );
                Thread.Sleep( 1000 );

                for ( int count = 1; count <= 10; count++ )
                {
                    try
                    {
                        var block = _cardReader.M1ReadBlock( block: 0 );
                        ConsoleWirter.Success( $"第{count}次 - M1卡号: {block.UID}, 块号: {block.BlockNo}, 数据: {block.BlockData}" );
                    }
                    catch ( Exception ex )
                    {
                        ConsoleWirter.Warning( $"第{count}次 - 读卡失败: {ex.Message}" );
                    }
                    finally
                    {
                        Thread.Sleep( 1000 );
                    }
                }
            }
        } );
    }
}